#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Croquette v1.0
By Michael Lee and David Gomes
Released August 1st, 2011
#
Please see /readme_Croquette.txt
Licensed under the MIT License (see /license_Croquette.txt)

Written in Python 2.7
"""

import os
import wx
import wx.stc as stc

import ticonverter

#TODO Make the following configurations in a text file
run_program = "wxwabbitemu"
faces = { 'times': 'Times',
          'mono' : 'Courier',
          'helv' : 'Helvetica',
          'other': 'new century schoolbook',
          'size' : 12,
          'size2': 10,
        }

class Editor(stc.StyledTextCtrl):
    """Editor Class, inherits wxStyledTextCtrl"""
    def __init__(self, parent):
        """Calls some functions and sets the Editor up"""
        super(Editor, self).__init__(parent)

        self.filename = ''
        self.directory = '.'
        self.filepath = ''
        self.indent_level = 0

        self.SetGenerics()        
        self.SetMargins()
        self.SetStyles()

    def SetGenerics(self):
        """Defines default configurations"""
        self.SetLexer(stc.STC_LEX_PYTHON) #is this giving us trouble? 
        self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) #set mono spacing here!
        self.SetTabWidth(4)
        self.SetIndentationGuides(1)
        #Indentation will only use space characters if useTabs is false
        self.SetUseTabs(False)

    def SetMargins(self):
        """Sets editor margins"""
        # margin 0 for breakpoints
        self.SetMarginSensitive(0, True)
        self.SetMarginType(0, wx.stc.STC_MARGIN_SYMBOL)
        self.SetMarginMask(0, 0x3)
        self.SetMarginWidth(0, 12)
        # margin 1 for current line arrow
        self.SetMarginSensitive(1, False)
        self.SetMarginMask(1, 0x4)
        # margin 2 for line numbers
        self.SetMarginType(2, stc.STC_MARGIN_NUMBER)
        self.SetMarginWidth(2, 28)

    def SetStyles(self, lang='python'):
        """Sets the styles"""

        #INDICATOR STYLES FOR ERRORS (self.errorMark)
        self.IndicatorSetStyle(2, stc.STC_INDIC_SQUIGGLE)
        self.IndicatorSetForeground(2, wx.RED)
        self.StyleSetSpec(stc.STC_P_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        
        # White space
        self.StyleSetSpec(stc.STC_P_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        # Number
        self.StyleSetSpec(stc.STC_P_NUMBER, "face:%(mono)s,fore:#007F7F,size:%(size)d" % faces)
        # String
        self.StyleSetSpec(stc.STC_P_STRING, "face:%(mono)s,fore:#7F007F,size:%(size)d" % faces)
        # Single quoted string
        self.StyleSetSpec(stc.STC_P_CHARACTER, "face:%(mono)s,fore:#7F007F,size:%(size)d" % faces)
        # Operators
        self.StyleSetSpec(stc.STC_P_OPERATOR, "face:%(mono)s,bold,size:%(size)d" % faces)
        # Identifiers
        self.StyleSetSpec(stc.STC_P_IDENTIFIER, "")
        # End of line where string is not closed
        self.StyleSetSpec(stc.STC_P_STRINGEOL, "face:%(mono)s,fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)

    def on_undo(self, event):
        """Checks if can Undo and if yes undoes"""
        if self.CanUndo() == 1:
            self.Undo()

    def on_redo(self, event):
        """Checks if can Redo and if yes redoes"""
        if self.CanRedo() == 1:
            self.Redo()

    def on_cut(self, event):
        """Cuts selected text"""
        self.Cut()

    def on_copy(self, event):
        """Copies selected text"""
        self.Copy()

    def on_paste(self, event):
        """Pastes selected text"""
        self.Paste()

    def on_clear(self, event):
        """Deletes selected text"""
        self.Clear()

    def on_select_all(self, event):
        """Selects all the text"""
        self.SelectAll()


class MainFrame(wx.Frame):
    """Class with the main frame, the GUI and the GUI Functions"""
    def __init__(self, parent,id):
        """Displays the frame, creates the GUI"""
        wx.Frame.__init__(self, parent,id,'Croquette', size=(800,600))
        self.create_gui()
        self.dirname = ""
        self.filepath = ""
        self.parser = ticonverter.Parser()

    def on_open(self, event):
        """Opens file for reading."""
        dlg = wx.FileDialog(self, "Open a file", self.dirname, 
                            "", "All files (*.*)|*.*|8xp files (.8xp)|*.8xp|txt files (.txt)|*.txt",
                            wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.file_name=dlg.GetFilename()
            self.dir_name=dlg.GetDirectory()

            file_path = os.path.join(self.dir_name, self.file_name)
            self.filepath = file_path #Update path
            
            self.SetTitle("%s - Croquette" % self.file_name)

            if self.parser.detect(file_path) == "8xp":
                self.text_input.SetText(
                    self.parser.convert_8xp_to_string(file_path))
            else:
                file_handle = open(file_path, "r")
                self.text_input.SetText(file_handle.read())
                file_handle.close()
                
    def on_save(self, event):
        """Saves a file into 8XP"""
        dlg = wx.FileDialog(self, "Save a file", self.dirname, 
                            "", "8xp files (.8xp)|*.8xp|txt files (.txt)|*.txt",
                            wx.SAVE | wx.OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:

            #Dirty hack to add .8xp to file ending
            self.file_name=dlg.GetFilename()
            if self.file_name[-4:].upper() != ".8XP":
                self.file_name += ".8xp"
            self.file_name = self.file_name.encode("ascii")

            self.dir_name=dlg.GetDirectory()
            self.path = os.path.join(self.dir_name, self.file_name)
            self.filepath = self.path

            self.parser.convert_string_to_8xp(self.text_input.GetText(),
                                              self.path, 
                                              self.file_name[:-4])
            
            self.SetTitle("%s - Croquette" % self.file_name)
        dlg.Destroy()

    def on_close(self, event):
        """Handles closing frame event"""
        dial = wx.MessageDialog(None,'Do you really want to exit?',
                        'Exit Python IDE',
                        wx.YES_NO | wx.ICON_QUESTION)

        if dial.ShowModal() == wx.ID_YES:
            self.Destroy()

    def on_run(self, event):
        """Runs a 8XP file"""
        os.system("%s %s" % (run_program, self.filepath))

    def create_gui(self):
        """Creates and displays the GUI and binds the events"""
        
        self.text_input = Editor(self)
        
        #Menu Bar Code
        menuBar = wx.MenuBar()
        fileMenu = wx.Menu()
        open_id = wx.NewId()
        fileMenu.Append(open_id, "Open\tCtrl+O")
        save_id = wx.NewId()
        fileMenu.Append(save_id, "Save\tCtrl+S")
        fileMenu.AppendSeparator()
        close_id = wx.NewId()
        fileMenu.Append(close_id, "Close\tCtrl+Q")
        editMenu = wx.Menu()
        undo_id = wx.NewId()
        editMenu.Append(undo_id, "Undo\tCtrl+Z")
        redo_id = wx.NewId()
        editMenu.Append(redo_id, "Redo\tCtrl+Y")
        editMenu.AppendSeparator()
        cut_id = wx.NewId()
        editMenu.Append(cut_id, "Cut\tCtrl+X")
        copy_id = wx.NewId()
        editMenu.Append(copy_id, "Copy\tCtrl+C")
        paste_id = wx.NewId()
        editMenu.Append(paste_id, "Paste\tCtrl+V")
        clear_id = wx.NewId()
        editMenu.Append(clear_id, "Delete")
        editMenu.AppendSeparator()
        select_all_id = wx.NewId()
        editMenu.Append(select_all_id, "Select All\tCtrl+A")
        run_id = wx.NewId()
        runMenu = wx.Menu()
        runMenu.Append(run_id, "Run\tF5")
        menuBar.Append(fileMenu, "&File")
        menuBar.Append(editMenu, "&Edit")
        menuBar.Append(runMenu, "&Run")
        self.SetMenuBar(menuBar)
        #End of Menu Bar Code

        self.Bind(wx.EVT_MENU, self.on_open, id=open_id)
        self.Bind(wx.EVT_MENU, self.on_save, id=save_id)
        self.Bind(wx.EVT_MENU, self.on_close, id=close_id)
        self.Bind(wx.EVT_CLOSE, self.on_close) #Called when user closes frame
        self.Bind(wx.EVT_MENU, self.text_input.on_undo, id=undo_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_redo, id=redo_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_cut, id=cut_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_copy, id=copy_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_paste, id=paste_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_clear, id=clear_id)
        self.Bind(wx.EVT_MENU, self.text_input.on_select_all, id=select_all_id)
        self.Bind(wx.EVT_MENU, self.on_run, id=run_id)

def start():
    """Displays the GUI and starts the GUI Loop"""
    app = wx.PySimpleApp()
    frame = MainFrame(parent=None, id=-1)
    frame.Show()
    #frame.Maximize()
    app.MainLoop()
    return


if __name__ == "__main__":
    start()
